package android.framework.media.octo;

import java.util.Locale;

import octoshape.osa2.OctoshapeSystem;
import octoshape.osa2.Problem;
import octoshape.osa2.StreamPlayer;
import octoshape.osa2.listeners.ProblemListener;
import octoshape.osa2.listeners.ProgressListener;
import octoshape.osa2.listeners.StatusChangedListener;
import octoshape.osa2.listeners.StreamPlayerListener;
import octoshape.osa2.listeners.StreamingAuthenticator;
import android.app.Activity;
import android.framework.util.L;
import android.net.Uri;

import com.octoshape.android.client.OctoshapePortListener;
import com.octoshape.android.client.OctoshapeSystemCreator;

/**
 * 
 * @ClassName: OctoshapeComponent
 * @Description: TODO
 * @author jtf19@163.com
 * @date 2013-7-20 上午12:07:11
 * 
 */
public class Octo {

	protected static final String TAG = "Octo";
	private OctoshapeSystem os;
	private OctoListener listener;
	private int port;
	private Activity activity;

	private String streamLink;
	protected Stream stream;
	private StreamPlayer sp;

	public Octo(OctoListener listener, Activity activity) {
		super();
		this.activity = activity;
		this.listener = listener;
		OctoshapeSystem.enableLog(true, "/mnt/sdcard/octoshape/");
		os = OctoshapeSystemCreator.create(activity, mProblemListener,
				mPortListener, Locale.getDefault().getLanguage());
		os.setProblemMessageLanguage(Locale.getDefault().getLanguage());
		os.setProblemListener(mProblemListener);
	}

	private ProblemListener mProblemListener = new ProblemListener() {

		@Override
		public void gotProblem(Problem p) {
			L.w(TAG, "Problem: " + p);
			if (p.hasProblemId("tooold")) { // dvr to the available maximum
				stream.requestDVR((int) StreamPlayer
						.getMaxLiveLatencyFromToooldProblem(p));
				listener.onOctoshapeProblem("Requested DVR : playing max DVR available ("
						+ StreamPlayer.getMaxLiveLatencyFromToooldProblem(p)
						+ ")");
			} else if (!p.hasProblemId("normal")) // errors to be displayed to
													// the user
				listener.onOctoshapeProblem("ERROR:\n" + p.getMessage()
						+ "\n\n [ " + p + " ] ");

		}

	};

	private OctoshapePortListener mPortListener = new OctoshapePortListener() {

		@Override
		public void onPortBound(int arg0) {
			L.d(TAG, "Port" + port + " was bound!");
			Octo.this.port = port;
			if (listener != null)
				listener.onOctoshapePrepared();
		}
	};

	public void addPlaybackInstance(String mediaPlayerId, String playerName,
			String playerVersion) {
		os.addPlayerNameAndVersion(mediaPlayerId, playerName, playerVersion);
	}

	public void open() {
		os.open();
	}

	public void finish() {
		if (os != null) {
			os.close(null);
		}
		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public int getOctoshapePort() {
		return port;
	}

	public OctoshapeSystem getOs() {
		return os;
	}

	public OctoListener getListener() {
		return listener;
	}

	public int getPort() {
		return port;
	}

	// //=====stream operrator========////////

	public Stream initStream(String streamLink) {
		this.streamLink = streamLink;
		sp = new StreamPlayer(os, this.streamLink);
		sp.setProgressListener(mProgressListener);
		sp.setListener(mStreamPlayerListener);
		sp.setStreamingAuthenticator(mStreamingAuthenticator);
		sp.setProblemListener(mProblemListener);
		sp.setStatusChangedListener(mStatusChangedListener);
		stream = new Stream(sp, this.streamLink);
		
		sp.initialize(false);
		
		L.d(TAG, "Stream: " + this.streamLink + " prepared!");
		return stream;
	}

	private StreamingAuthenticator mStreamingAuthenticator = new StreamingAuthenticator() {

		@Override
		public void authenticateId(String autoId, StreamPlayer sp) {
			// TODO Auto-generated method stub
			autoId += ",";
			sp.setAuthorization("", getPassword(autoId));

		}

	};

	private StatusChangedListener mStatusChangedListener = new StatusChangedListener() {

		@Override
		public void statusChanged(byte oldStatus, byte newStatus) {
			L.d(TAG, "Changes status for " + streamLink + ": "
					+ (int) oldStatus + " to " + (int) newStatus);
		}
	};

	private ProgressListener mProgressListener = new ProgressListener() {

		@Override
		public void gotProgress(int percent) {
			L.d(TAG, "Progress for " + streamLink + ": " + percent + "%");
		}

	};

	private StreamPlayerListener mStreamPlayerListener = new StreamPlayerListener() {

		@Override
		public void gotUrl(final String url, final long seekOffset,
				final boolean playAfterBuffer) {

			L.w(TAG, "gotUrl: " + url);
			L.w(TAG, "seekOffset: " + seekOffset);
			L.w(TAG, "playAfterBuffer: " + playAfterBuffer);

			stream.playerURL = Uri.parse(url);
			stream.osaSeekOffset = seekOffset;
			activity.runOnUiThread(new Runnable() {
				@Override
				public void run() {
					if (seekOffset > 0)
						listener.onOSASeekCompleted(stream, stream.playerURL,
								seekOffset);
					else
						listener.onStreamPrepared(stream, stream.playerURL,
								playAfterBuffer);
				}
			});
		}

		@Override
		public void gotNewOnDemandStreamDuration(long duration) {
			stream.fileDuration = duration;
		}

		@Override
		public void resolvedNativeSeek(boolean isLive, String playerId) {
			L.w(TAG, streamLink + ": resolvedNativeSeek: ");
			stream.isLive = isLive;

			stream.nativeSeek = true;
			stream.selectedPlayerId = playerId;
		}

		@Override
		public void resolvedNoSeek(boolean isLive, String playerId) {
			L.w(TAG, streamLink + ": resolvedNoSeek: ");
			stream.isLive = isLive;
			stream.selectedPlayerId = playerId;
		}

		@Override
		public void resolvedOsaSeek(boolean isLive, long duration,
				String playerId) {
			L.w(TAG, streamLink + ": resolvedOsaSeek: ");
			stream.isLive = isLive;
			stream.nativeSeek = false;
			stream.osaSeek = true;
			if (!isLive)
				stream.fileDuration = duration;
			else
				stream.liveMaxLatency = duration;

			stream.selectedPlayerId = playerId;
		}

	};

	public static String getPassword(String authid) {
		try {
			java.security.MessageDigest md = java.security.MessageDigest
					.getInstance("MD5");
			String input = "4gZQLal7A6PeyIG" + "," + authid;
			// System.out.println("input=["+input+"]");
			byte[] b = md.digest(input.getBytes());
			StringBuffer hexmd5 = new StringBuffer();
			for (int i = 0; i < b.length; i++) {
				hexmd5.append(Integer.toString((b[i] & 0xff) + 0x100, 16)
						.substring(1));
			}
			return hexmd5.toString();
		} catch (Exception e) {
			return null;
		}
	}

}
